// 飞行
export const flyTo = (viewer, position, callback) => {
  viewer.camera.flyTo({
    destination: Cesium.Cartesian3.fromDegrees(
      position.lon,
      position.lat,
      position.height
    ), //设置位置
    orientation: {
      heading: Cesium.Math.toRadians(position.heading),
      pitch: Cesium.Math.toRadians(position.pitch),
      roll: Cesium.Math.toRadians(position.roll),
    },
    complete: callback && callback(),
    maximumHeight: 1000,
    pitchAdjustHeight: 500,
    duration: 2,
  })
}

// 加载矢量图层
export const addLayer = (viewer, url, tileWidth = 512) => {
  let tileMatrix =
    tileWidth === 512
      ? [
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
      : [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
  const imageLayer = new Cesium.ImageryLayer(
    new Cesium.WebMapTileServiceImageryProvider({
      url,
      layer: '',
      style: '',
      format: '',
      tileMatrixSetID: '',
      tileWidth: tileWidth,
      tileHeight: tileWidth,
      tilingScheme: new Cesium.GeographicTilingScheme(),
      tileMatrixLabels: tileMatrix,
      maximumLevel: 22,
    })
  )
  viewer.imageryLayers.add(imageLayer)
  return imageLayer
}

// 加载矢量图层
export const addChangeMapLayer = (viewer, url, tileWidth = 512) => {
  let tileMatrix =
    tileWidth === 512
      ? [
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
      : [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
  let obj = new Cesium.WebMapTileServiceImageryProviderExt(viewer, {
    url,
    layer: '',
    style: '',
    format: '',
    tileMatrixSetID: '',
    tileWidth: tileWidth,
    tileHeight: tileWidth,
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: tileMatrix,
    maximumLevel: 22,
  })
  const imageLayer = new Cesium.ImageryLayer(obj)
  viewer.imageryLayers.add(imageLayer)
  return { imageLayer, obj }
}

// 加载随时间改变矢量图层
export const addChangeLayer = (viewer, url) => {
  let vectorLayer = new Cesium.VectorTileServiceImageryProvider(viewer, {
    url,
    tilingScheme: new Cesium.GeographicTilingScheme({
      numberOfLevelZeroTilesX: 2,
      numberOfLevelZeroTilesY: 1,
    }),
    tileMatrixLabels: [
      '2',
      '3',
      '4',
      '5',
      '6',
      '7',
      '8',
      '9',
      '10',
      '11',
      '12',
      '13',
      '14',
      '15',
      '16',
      '17',
      '18',
      '19',
      '20',
      '21',
      '22',
    ],
    maximumLevel: 26,
    tileWidth: 512,
    tileHeight: 512,
    dataType: 'binary',
    //是否需要数据解码
    needDecode: false,
    ratio: 2,
    showLevel: 6,
  })
  var layer = new Cesium.ImageryLayer(vectorLayer)
  viewer.imageryLayers.add(layer)
  return { vectorLayer, layer }
}

// 加载覆盖在三维的矢量图层
export const addCoverLayer = (viewer, url, tileWidth = 512) => {
  let tileMatrix =
    tileWidth === 512
      ? [
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
      : [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
  let coverLayer = new Cesium.EnvelopeWmtsImageryProvider(viewer, {
    url,
    layer: '',
    style: '',
    format: '',
    tileMatrixSetID: '',
    tileWidth: width,
    tileHeight: width,
    tilingScheme: new Cesium.GeographicTilingScheme(),
    tileMatrixLabels: tileMatrix,
    maximumLevel: 22,
  })

  const modelAddLayer = viewer.imageryLayers.addImageryProvider(coverLayer)
  return modelAddLayer
}

// 加载注记
export const addLabelLayer = (viewer, url, tileWidth = 512) => {
  let tileMatrix =
    tileWidth === 512
      ? [
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
      : [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]

  const lableLayer = new Cesium.ImageryLayer(
    new Cesium.LabelTileServiceImageryProvider(viewer, {
      url,
      tilingScheme: new Cesium.GeographicTilingScheme({
        numberOfLevelZeroTilesX: 2,
        numberOfLevelZeroTilesY: 1,
      }),
      tileMatrixLabels: tileMatrix,
      maximumLevel: 22,
      tileWidth: tileWidth,
      tileHeight: tileWidth,
      dataType: 'binary',
      needDecode: false,
      fontName: '微软雅黑',
      glyphUrl: 'fonts/{fontstack}/{range}.pbf',
      defaultHeight: 63,
    })
  )
  viewer.imageryLayers.add(lableLayer)
  return lableLayer
}

//矢量图层叠加在三维模型上默认图层
export const addModelLayer = (viewer, url, tileWidth = 512) => {
  let tileMatrix =
    tileWidth === 512
      ? [
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
      : [
          '1',
          '2',
          '3',
          '4',
          '5',
          '6',
          '7',
          '8',
          '9',
          '10',
          '11',
          '12',
          '13',
          '14',
          '15',
          '16',
          '17',
          '18',
          '19',
          '20',
          '21',
          '22',
        ]
  const modelAddLayer = new Cesium.ImageryLayer(
    new Cesium.EnvelopeWmtsImageryProvider(viewer, {
      url,
      layer: '',
      style: '',
      format: '',
      tileMatrixSetID: '',
      tileWidth: tileWidth,
      tileHeight: tileWidth,
      tilingScheme: new Cesium.GeographicTilingScheme(),
      tileMatrixLabels: tileMatrix,
      maximumLevel: 22,
    })
  )
  viewer.imageryLayers.add(modelAddLayer)
  return modelAddLayer
}

// 加载天地图
export const addTDTLayer = (viewer, url) => {
  const imageLayer = new Cesium.ImageryLayer(
    new Cesium.WebMapTileServiceImageryProvider({
      url,
      layer: 'tdtImg_c',
      style: 'default',
      format: 'tiles',
      tileMatrixSetID: 'c',
      subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],
      tilingScheme: new Cesium.GeographicTilingScheme(),
      tileMatrixLabels: [
        '1',
        '2',
        '3',
        '4',
        '5',
        '6',
        '7',
        '8',
        '9',
        '10',
        '11',
        '12',
        '13',
        '14',
        '15',
        '16',
        '17',
        '18',
      ],
      maximumLevel: 17,
    })
  )
  viewer.imageryLayers.add(imageLayer)
  return imageLayer
}

// 加载 arcgis 图层
export const addArcgis = (viewer, url) => {
  let arcgistLayer = new Cesium.ArcGisMapServerImageryProvider({
    url,
  })
  const layer = viewer.imageryLayers.addImageryProvider(arcgistLayer)
  return layer
}

// 删除图层
export const removeLayer = (viewer, layer) => {
  if (!layer) return
  if (Array.isArray(layer)) {
    layer.forEach((item) => {
      viewer.imageryLayers.remove(item)
    })
    layer = []
  } else {
    viewer.imageryLayers.remove(layer)
    layer = null
  }
}

// 加载模型
export const addModel = (tile3dUrl) => {
  const tile3d = new Cesium.Cesium3DTileset({
    url: tile3dUrl,
    showFS: false,
    showVS: false,
    maximumScreenSpaceError: 16,
    dynamicScreenSpaceError: true,
    dynamicScreenSpaceErrorDensity: 0.00278,
    dynamicScreenSpaceErrorFactor: 4.0,
    dynamicScreenSpaceErrorFactorHeightFalloff: 0.25,
    maximumMemoryUsage: 1024,
    skipLevelOfDetail: true,
    immediatelyLoadDesiredLevelOfDetail: true,
  })
  return tile3d
}

// 加载聚合模型
export const addPolymerizationModel = (tieUrl) => {
  const tile3d = new Cesium.Cesium3DTileset({
    url: tieUrl,
    skipLevelOfDetail: true,
    immediatelyLoadDesiredLevelOfDetail: true,
    maximumMemoryUsage: window.maximumMemoryUsage,
    subdomains: ['124.70.104.88:8030', '124.70.104.88:8086'], // 多通道下载
  })
  return tile3d
}

// 删除 primitives
export const removePrimitives = (viewer, value) => {
  if (!value) return
  if (Array.isArray(value)) {
    value.forEach((item) => {
      viewer.scene.primitives.remove(item)
    })
    value = []
  } else {
    viewer.scene.primitives.remove(value)
    value = null
  }
  return value
}

// 获取高度
export const getHigh = (position, callback, params) => {
  const promise = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, [
    position,
  ])
  promise.then((data) => {
    if (typeof callback === 'function') {
      callback(data, params)
    }
  })
}

// 添加浮云框
export const addOverlay = (viewer, element, position, x = 0, y = 0) => {
  let option = {
    element: element,
    position: position,
    offset: {
      //默认整个div的左上角，跟地图上指定的点重合
      x: x, //向屏幕左边平移的像素值
      y: y, //向屏幕下方平移的像素值
    },
  }
  var currOverlay = new Cesium.Overlay(option)
  viewer.addOverlay(currOverlay)
  return currOverlay
}

// 删除浮云框
export const removePopup = (currOverlay) => {
  if (!currOverlay) return null
  if (Array.isArray(currOverlay)) {
    currOverlay.forEach((item) => {
      if (item.ele) {
        item.ele.destroy()
      } else {
        item.destroy()
      }
    })
    currOverlay = []
  } else {
    currOverlay.destroy()
    currOverlay = null
  }
  return null
}

/**
 * 解析GeoJSON的不同几何类型，并将解析后的结果转换为一个包含经度和纬度的嵌套数组
 *
 * @param {object} geojson - GeoJSON对象
 * @returns {Array} 包含经度和纬度的嵌套数组
 */
export function parseGeoJSON(geojson) {
  const coordinatesArray = []

  function extractCoordinates(coordinates) {
    if (Array.isArray(coordinates)) {
      coordinates.forEach((coord) => {
        if (Array.isArray(coord[0]) && Array.isArray(coord[0][0])) {
          // 处理多层嵌套的情况，如Polygon的内部环
          extractCoordinates(coord)
        } else if (Array.isArray(coord)) {
          // 处理单层嵌套的情况，如Point, LineString
          coordinatesArray.push(coord)
        }
      })
    }
  }

  if (geojson.type === 'FeatureCollection') {
    geojson.features.forEach((feature) => {
      if (feature.geometry) {
        extractCoordinates(feature.geometry.coordinates)
      }
    })
  } else if (geojson.type === 'Feature') {
    if (geojson.geometry) {
      extractCoordinates(geojson.geometry.coordinates)
    }
  } else if (
    geojson.type === 'Point' ||
    geojson.type === 'LineString' ||
    geojson.type === 'Polygon' ||
    geojson.type === 'MultiPoint' ||
    geojson.type === 'MultiLineString' ||
    geojson.type === 'MultiPolygon'
  ) {
    extractCoordinates(geojson.coordinates)
  }

  return coordinatesArray
}

// 根据经纬度数组找到合适的高度
export function findHeight(polygonCoordinates) {
  // 将经纬度数组转换为 Cartesian3 数组
  const positions = polygonCoordinates.map((coord) =>
    Cesium.Cartesian3.fromDegrees(coord[0], coord[1])
  )

  // 计算多边形的边界框
  const cartographicPositions = positions.map((position) =>
    Cesium.Cartographic.fromCartesian(position)
  )
  const minLongitude = Math.min(
    ...cartographicPositions.map((pos) => Cesium.Math.toDegrees(pos.longitude))
  )
  const maxLongitude = Math.max(
    ...cartographicPositions.map((pos) => Cesium.Math.toDegrees(pos.longitude))
  )
  const minLatitude = Math.min(
    ...cartographicPositions.map((pos) => Cesium.Math.toDegrees(pos.latitude))
  )
  const maxLatitude = Math.max(
    ...cartographicPositions.map((pos) => Cesium.Math.toDegrees(pos.latitude))
  )

  const boundingBox = {
    x: minLongitude,
    y: minLatitude,
    width: maxLongitude - minLongitude,
    height: maxLatitude - minLatitude,
  }
  const area = boundingBox.width * boundingBox.height
  const alt = Math.sqrt(area) * 200000 // 示例计算，可以根据实际情况调整

  return { ...boundingBox, alt }
}

//获取当前视角的四至
export const getViewFourPoint = (viewer) => {
  const extend = viewer.camera.computeViewRectangle()
  const params = {}
  if (typeof extend === 'undefined') {
    const coordToLonlat = (viewer, x, y) => {
      const { camera, scene } = viewer
      const d2 = new Cesium.Cartesian2(x, y)
      const ellipsoid = scene.globe.ellipsoid
      //2D转3D世界坐标
      const d3 = camera.pickEllipsoid(d2, ellipsoid)
      //3D世界坐标转弧度
      const upperLeftCartographic =
        scene.globe.ellipsoid.cartesianToCartographic(d3)
      //弧度转经纬度
      const lon = Cesium.Math.toDegrees(upperLeftCartographic.longitude)
      const lat = Cesium.Math.toDegrees(upperLeftCartographic.latitude)
      return { lon, lat }
    }
    const canvas = viewer.scene.canvas
    const upperLeftLonLat = coordToLonlat(viewer, 0, 0)
    const lowerRightLonLat = coordToLonlat(
      viewer,
      canvas.clientWidth,
      canvas.clientHeight
    )
    params.xmin = upperLeftLonLat.lon
    params.xmax = lowerRightLonLat.lon
    params.ymin = upperLeftLonLat.lat
    params.ymax = lowerRightLonLat.lat
  } else {
    //三维视图
    params.xmax = Cesium.Math.toDegrees(extend.east)
    params.ymax = Cesium.Math.toDegrees(extend.north)
    params.xmin = Cesium.Math.toDegrees(extend.west)
    params.ymin = Cesium.Math.toDegrees(extend.south)
  }
  return params
}

// 添加水面
export const addWater = (bottmHeight, topHeight, pos) => {
  let appearance = new Cesium.EllipsoidSurfaceAppearance({
    material: Cesium.Material.fromType(Cesium.ReflexWaterMaterialType, {
      WaveImage: 'images/water.jpg',
      bottomImage: 'images/shazi.jpg',
      repeat: new Cesium.Cartesian2(1, 1),
      RainState: true, // 是否有溅落的雨滴
      RainSize: 0.3, // 浮点型，雨滴溅落在水面的size
      RainNoiseImage: 'images/rain.png', // 雨滴的噪声图
      wateralpha: 0.7,
    }),
  })

  let geometryInstances = []
  let polygonInstance = new Cesium.GeometryInstance({
    geometry: Cesium.PolygonGeometry.fromPositions({
      positions: Cesium.Cartesian3.fromDegreesArray(pos),
      height: bottmHeight,
      extrudedHeight: topHeight,
      vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
    }),
    attributes: {
      color: Cesium.ColorGeometryInstanceAttribute.fromColor(
        Cesium.Color.fromCssColorString('#ff0000').withAlpha(0.5)
      ),
    },
  })
  geometryInstances.push(polygonInstance)

  // 水面材质
  let waterLayer = new Cesium.Primitive({
    show: true,
    geometryInstances: geometryInstances,
    undisplayable: true,
    appearance: appearance,
  })
  viewer.scene.primitives.add(waterLayer)
  return waterLayer
}

//解析geojson获取高度
// 获取高度
export const GetPositionBygeojson = (viewer, posArr, promote = 0) => {
  return new Promise(function (resolve) {
    let lonlat = []
    posArr.forEach((item) => {
      lonlat.push(
        new Cesium.Cartographic(
          Cesium.Math.toRadians(Number(item.longitude)),
          Cesium.Math.toRadians(Number(item.latitude))
        )
      )
    })
    let finalArr = []
    //模型上取点
    const promise = viewer.scene.sampleHeightMostDetailed(lonlat) //这里可以传多个点

    promise.then((data) => {
      data.forEach((obj, index) => {
        if (obj && obj.height) {
          finalArr[index] = [
            posArr[index].lon,
            posArr[index].lat,
            obj.height + promote,
          ]
        } else {
          finalArr[index] = []
        }
      })
    })

    //地形上取点
    const promise1 = Cesium.sampleTerrainMostDetailed(
      viewer.terrainProvider,
      lonlat
    )
    promise1.then((data) => {
      data.forEach((obj, index) => {
        if (finalArr[index] && finalArr[index].height) {
          //这里就是判断是不是已经在模型上取点
        } else {
          finalArr[index] = [
            posArr[index].lon,
            posArr[index].lat,
            obj.height + promote,
          ]
        }
      })
      resolve(finalArr)
    })
  })
}

// 获取高度
export const GetPositionBylonlat = (viewer, posArr, promote = 0) => {
  return new Promise(function (resolve) {
    let lonlat = []
    posArr.forEach((item) => {
      lonlat.push(
        new Cesium.Cartographic(
          Cesium.Math.toRadians(item.lon),
          Cesium.Math.toRadians(item.lat)
        )
      )
    })
    let finalArr = []
    //模型上取点
    const promise = viewer.scene.sampleHeightMostDetailed(lonlat) //这里可以传多个点
    promise.then((data) => {
      data.forEach((obj, index) => {
        if (obj && obj.height) {
          finalArr[index] = Cesium.Cartesian3.fromDegrees(
            posArr[index].lon,
            posArr[index].lat,
            obj.height + promote
          )
        } else {
          finalArr[index] = []
        }
      })
    })

    //地形上取点
    const promise1 = Cesium.sampleTerrainMostDetailed(
      viewer.terrainProvider,
      lonlat
    )
    promise1.then((data) => {
      data.forEach((obj, index) => {
        if (finalArr[index] && finalArr[index].height) {
          //这里就是判断是不是已经在模型上取点
        } else {
          finalArr[index] = Cesium.Cartesian3.fromDegrees(
            posArr[index].lon,
            posArr[index].lat,
            obj.height + promote
          )
        }
      })
      resolve(finalArr)
    })
  })
}

// 添加高亮
export const addHighlight = (viewer, data) => {
  let ele = new Cesium.ClassificationPrimitive({
    geometryInstances: [],
    classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
    asynchronous: false,
    appearance: new Cesium.PerInstanceColorAppearance({
      closed: true,
      translucent: true,
    }),
  })

  let polygonInstance = new Cesium.GeometryInstance({
    id: data.id,
    geometry: Cesium.PolygonGeometry.fromPositions({
      positions: Cesium.Cartesian3.fromDegreesArray(data.positions),
      height: data.height,
      extrudedHeight: data.extrudedHeight,
      vertexFormat: Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT,
    }),

    attributes: {
      color: Cesium.ColorGeometryInstanceAttribute.fromColor(
        Cesium.Color.fromCssColorString(data.color).withAlpha(
          data.opacity || 0.4
        )
      ),
    },
  })
  ele.geometryInstances.push(polygonInstance)
  viewer.scene.primitives.add(ele)
  return ele
}

// 视频融合
export const addVideo = (viewer, params) => {
  const cameraVideo = new Cesium.Video(viewer, {
    position: { x: params.x, y: params.y, z: params.z },
    offsetDis: params.offsetDis ? params.offsetDis : -82,
    alpha: params.alpha ? params.alpha : 0.8,
    near: params.near ? params.near : 1,
    far: params.far ? params.far : 1000,
    heading: params.heading ? params.heading : 15.28,
    pitch: params.pitch ? params.pitch : -89.225,
    aspectRatio: params.aspectRatio ? params.aspectRatio : 1.78,
    videoType: params.videoType ? params.videoType : 'mp4',
    videoSource: params.videoSource,
    useMask: true,
    maskUrl: `duofengshuiku/mask.png`,
    debugFrustum: false,
  })
  viewer.scene.primitives.add(cameraVideo)
  return cameraVideo
}

// 删除视频融合
export const removeVideo = (viewer, cameraVideo) => {
  if (!cameraVideo || cameraVideo.length == 0) return

  if (Array.isArray(cameraVideo)) {
    cameraVideo.forEach((item) => {
      viewer.scene.primitives.remove(item)
      item.destroy()
      item = null
    })
    cameraVideo = []
  } else {
    viewer.scene.primitives.remove(cameraVideo)
    cameraVideo.destroy()
    cameraVideo = null
  }
}

//点击取一个点
export const pickOnePoint = (
  viewer,
  callback,
  tooltipText = '请单击选择一个地点'
) => {
  let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  let tooltip = document.createElement('DIV')
  document.body.appendChild(tooltip)
  tooltip.style =
    'position: absolute;background: rgba(0,0,0,0.5); z-index: 999;line-height: 18px;pointer-events: none;'
  tooltip.innerHTML = `<span class="prompt-text" style="color: #fff; font-size: 12px;padding:4px;">${tooltipText}</span>`
  tooltip.style.display = 'block'

  handlers.setInputAction((movement) => {
    var pickedObject = viewer.scene.pick(movement.position)
    var cartesian
    if (!pickedObject) {
      if (viewer.scene.globe.depthTestAgainstTerrain) {
        cartesian = viewer.scene.pickPosition(movement.position)
      } else {
        //如果没开启深度检测
        var pickRay = viewer.scene.camera.getPickRay(movement.position)
        cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
      }
    } else {
      cartesian = viewer.scene.pickPosition(movement.position)
    }

    var ellipsoid = viewer.scene.globe.ellipsoid
    var cartographic = ellipsoid.cartesianToCartographic(cartesian)
    var lat = Cesium.Math.toDegrees(cartographic.latitude)
    var lon = Cesium.Math.toDegrees(cartographic.longitude)
    var height = cartographic.height

    callback({
      cartesian,
      lon,
      lat,
      height,
    })

    document.body.removeChild(tooltip)

    handlers && handlers.destroy()
    handlers = null
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handlers.setInputAction((movement) => {
    tooltip.style.left = movement.endPosition.x + 5 + 'px'
    tooltip.style.top = movement.endPosition.y - 28 + 'px'
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}

//单击连续取点，双击结束选点
export const pickMorePoint = (
  viewer,
  callback,
  endCb,
  tooltipText = '左键单击选点，右键单击退出'
) => {
  let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  let tooltip = document.createElement('DIV')
  document.body.appendChild(tooltip)
  tooltip.style =
    'position: absolute;background: rgba(0,0,0,0.5); z-index: 999;line-height: 18px;pointer-events: none;'
  tooltip.innerHTML = `<span class="prompt-text" style="color: #fff; font-size: 12px;padding:4px;">${tooltipText}</span>`
  tooltip.style.display = 'block'

  handlers.setInputAction((movement) => {
    var pickedObject = viewer.scene.pick(movement.position)
    var cartesian
    if (!pickedObject) {
      if (viewer.scene.globe.depthTestAgainstTerrain) {
        cartesian = viewer.scene.pickPosition(movement.position)
      } else {
        //如果没开启深度检测
        var pickRay = viewer.scene.camera.getPickRay(movement.position)
        cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
      }
    } else {
      cartesian = viewer.scene.pickPosition(movement.position)
    }

    var ellipsoid = viewer.scene.globe.ellipsoid
    var cartographic = ellipsoid.cartesianToCartographic(cartesian)
    var lat = Cesium.Math.toDegrees(cartographic.latitude)
    var lon = Cesium.Math.toDegrees(cartographic.longitude)
    var height = cartographic.height

    callback({
      cartesian,
      lon,
      lat,
      height,
    })
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handlers.setInputAction((movement) => {
    tooltip.style.left = movement.endPosition.x + 5 + 'px'
    tooltip.style.top = movement.endPosition.y - 28 + 'px'
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  handlers.setInputAction((movement) => {
    document.body.removeChild(tooltip)
    handlers && handlers.destroy()
    handlers = null
    endCb && endCb()
  }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
}

//选取点然后连成线
export const pickPointAndLine = (
  viewer,
  callback,
  tooltipText = '单击选点，双击选结束点'
) => {
  let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  let tooltip = document.createElement('DIV')
  document.body.appendChild(tooltip)
  tooltip.style =
    'position: absolute;background: rgba(0,0,0,0.5); z-index: 999;line-height: 18px;pointer-events: none;'
  tooltip.innerHTML = `<span class="prompt-text" style="color: #fff; font-size: 12px;padding:4px;">${tooltipText}</span>`
  tooltip.style.display = 'block'

  let positions = []
  let _lineEntity = new Cesium.Entity()

  handlers.setInputAction((movement) => {
    var pickedObject = viewer.scene.pick(movement.position)
    var cartesian
    if (!pickedObject) {
      if (viewer.scene.globe.depthTestAgainstTerrain) {
        cartesian = viewer.scene.pickPosition(movement.position)
      } else {
        //如果没开启深度检测
        var pickRay = viewer.scene.camera.getPickRay(movement.position)
        cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
      }
    } else {
      cartesian = viewer.scene.pickPosition(movement.position)
    }

    var ellipsoid = viewer.scene.globe.ellipsoid
    var cartographic = ellipsoid.cartesianToCartographic(cartesian)
    var lat = Cesium.Math.toDegrees(cartographic.latitude)
    var lon = Cesium.Math.toDegrees(cartographic.longitude)
    var height = cartographic.height
    if (height > -3) {
      if (positions.length < 2) {
        //多加一个初始点  第一次移动的时候会删除
        positions.push(Cesium.Cartesian3.fromDegrees(lon, lat, height + 1))
      }
      positions.push(Cesium.Cartesian3.fromDegrees(lon, lat, height + 1))
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handlers.setInputAction((movement) => {
    tooltip.style.left = movement.endPosition.x + 5 + 'px'
    tooltip.style.top = movement.endPosition.y - 28 + 'px'

    if (positions.length >= 2) {
      var pickedObject = viewer.scene.pick(movement.endPosition)

      var cartesian
      if (!pickedObject) {
        if (viewer.scene.globe.depthTestAgainstTerrain) {
          cartesian = viewer.scene.pickPosition(movement.endPosition)
        } else {
          //如果没开启深度检测
          var pickRay = viewer.scene.camera.getPickRay(movement.endPosition)
          cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
        }
      } else {
        cartesian = viewer.scene.pickPosition(movement.endPosition)
      }
      if (cartesian && cartesian.x) {
        positions.pop()
        positions.push(cartesian)
      }
    }
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  handlers.setInputAction((movement) => {
    if (positions.length < 1) {
      alert('请至少选择两个点!')
      return
    }
    //删除最后一个点一起携带的漂移点
    positions.pop()
    positions.pop()
    callback(positions)
    document.body.removeChild(tooltip)
    viewer.entities.remove(_lineEntity)
    handlers && handlers.destroy()
    handlers = null
  }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

  _lineEntity.polyline = {
    width: 5,
    arcType: Cesium.ArcType.RHUMB,
    material: Cesium.Color.fromCssColorString('#90EE90').withAlpha(0.8),
  }
  _lineEntity.polyline.positions = new Cesium.CallbackProperty(function () {
    return positions
  }, false)
  viewer.entities.add(_lineEntity)
}

//选取点然后形成面
export const pickPointAndPolygon = (
  viewer,
  callback,
  tooltipText = '单击选点，双击选结束绘制面'
) => {
  viewer.screenSpaceEventHandler.removeInputAction(
    Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
  )
  let handlers = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  let tooltip = document.createElement('DIV')
  document.body.appendChild(tooltip)
  tooltip.style =
    'position: absolute;background: rgba(0,0,0,0.5); z-index: 999;line-height: 18px;pointer-events: none;'
  tooltip.innerHTML = `<div id="tooltip-text" style="color: #fff; font-size: 12px;padding:4px;">${tooltipText}</div>`
  tooltip.style.display = 'block'

  let positions = []
  let lonlat = []

  let _polygonObj = null

  let pointEneityList = []

  let polygon = new Cesium.PolygonHierarchy()
  polygon.positions = positions

  handlers.setInputAction((movement) => {
    var pickedObject = viewer.scene.pick(movement.position)
    var cartesian
    if (!pickedObject) {
      if (viewer.scene.globe.depthTestAgainstTerrain) {
        cartesian = viewer.scene.pickPosition(movement.position)
      } else {
        //如果没开启深度检测
        var pickRay = viewer.scene.camera.getPickRay(movement.position)
        cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
      }
    } else {
      cartesian = viewer.scene.pickPosition(movement.position)
    }

    if (cartesian) {
      positions.push(cartesian)
      var ellipsoid = viewer.scene.globe.ellipsoid
      var cartographic = ellipsoid.cartesianToCartographic(cartesian)
      var lat = Cesium.Math.toDegrees(cartographic.latitude)
      var lon = Cesium.Math.toDegrees(cartographic.longitude)
      lonlat.push([lon, lat])

      let pointEneity = viewer.entities.add({
        show: true,
        position: cartesian,
        point: {
          color: Cesium.Color.fromCssColorString('#f00'),
          pixelSize: 8,
          outlineColor: Cesium.Color.fromCssColorString('#fff'),
          outlineWidth: 2,
          disableDepthTestDistance: Number.POSITIVE_INFINITY, // 无论如何缩放，标记点不被地形遮挡
        },
      })

      pointEneityList.push(pointEneity)

      if (!_polygonObj) {
        create()
      }
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

  handlers.setInputAction((movement) => {
    tooltip.style.left = movement.endPosition.x + 5 + 'px'
    tooltip.style.top = movement.endPosition.y - 28 + 'px'
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

  handlers.setInputAction((movement) => {
    var pickedObject = viewer.scene.pick(movement.position)
    var cartesian
    if (!pickedObject) {
      if (viewer.scene.globe.depthTestAgainstTerrain) {
        cartesian = viewer.scene.pickPosition(movement.position)
      } else {
        //如果没开启深度检测
        var pickRay = viewer.scene.camera.getPickRay(movement.position)
        cartesian = viewer.scene.globe.pick(pickRay, viewer.scene)
      }
    } else {
      cartesian = viewer.scene.pickPosition(movement.position)
    }
    if (cartesian) {
      positions.push(cartesian)
    }

    document.body.removeChild(tooltip)

    pointEneityList.forEach((item) => {
      viewer.entities.remove(item)
    })

    handlers && handlers.destroy()
    handlers = null
    lonlat.push(lonlat[0])
    callback(lonlat, _polygonObj)
  }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

  const create = () => {
    let _polygonEntity = new Cesium.Entity()

    _polygonEntity.polygon = {
      hierarchy: new Cesium.CallbackProperty(function () {
        return polygon
      }, false),

      material: Cesium.Color.fromCssColorString('#7FFF00').withAlpha(0.4),
      outline: true,
      outlineColor: Cesium.Color.fromCssColorString('#7FFF00'),
    }

    _polygonObj = viewer.entities.add(_polygonEntity)
  }
}

// 根据传入的geojson数据绘制线
export const drawLineByGeojson = (
  viewer,
  data,
  color = 'rgb(0,240,255)',
  alpha = 0.4,
  width = 5,
  type = 'ground'
) => {
  let geojson = new Cesium.Geojson().read(data)
  let methodName = {
    ground: {
      primitive: 'GroundPolylinePrimitive',
      geometry: 'GroundPolylineGeometry',
    },
    default: {
      primitive: 'Primitive',
      geometry: 'PolylineGeometry',
    },
  }
  let primitives = []
  geojson.lineArray.forEach((item) => {
    let positions = Cesium.Cartesian3.fromDegreesArray(item.geometry)
    let polylinePrimitive = new Cesium[methodName[type].primitive]({
      geometryInstances: new Cesium.GeometryInstance({
        geometry: new Cesium[methodName[type].geometry]({
          positions: positions,
          width: width,
          vertexFormat: Cesium.PolylineColorAppearance.VERTEX_FORMAT,
        }),
        attributes: {
          color: Cesium.ColorGeometryInstanceAttribute.fromColor(
            Cesium.Color.fromCssColorString(color).withAlpha(alpha)
          ),
        },
      }),
      appearance: new Cesium.PolylineColorAppearance(),
    })
    viewer.scene.primitives.add(polylinePrimitive)
    primitives.push(polylinePrimitive)
  })
  return primitives
}

// 根据传入的geojson数据绘制面
export const drawPolygonByGeojson = (
  viewer,
  data,
  color = 'rgb(0,240,255)',
  alpha = 0.4
) => {
  let geojson = new Cesium.Geojson().read(data)
  let primitives = []
  geojson.polygonArray.forEach((item) => {
    // 定义面的外轮廓
    let outerRing = Cesium.Cartesian3.fromDegreesArray(item.geometry.pts)
    // 定义内环
    let holes = []
    if (item.geometry.holes.length > 0) {
      item.geometry.holes.forEach((hole) => {
        holes.push(Cesium.Cartesian3.fromDegreesArray(hole))
      })
    }
    // 创建多边形层次结构
    let hierarchy = holes
      ? new Cesium.PolygonHierarchy(outerRing, holes)
      : new Cesium.PolygonHierarchy(outerRing)
    // 创建几何实例
    let primitive = new Cesium.GroundPrimitive({
      geometryInstances: new Cesium.GeometryInstance({
        geometry: new Cesium.PolygonGeometry({
          polygonHierarchy: hierarchy,
          perPositionHeight: true,
        }),
      }),
      appearance: new Cesium.MaterialAppearance({
        material: Cesium.Material.fromType('Color', {
          color: Cesium.Color.fromCssColorString(color).withAlpha(alpha),
        }),
      }),
    })
    viewer.scene.primitives.add(primitive)
    primitives.push(primitive)
  })
  return primitives
}

/**
 * 是否为相邻的两个点，连续单击或者双击会出现此情况
 * @param {*} movement
 * @returns
 */
const isNearPoint = (movement) => {
  //下面代码是 避免双击带来的2次click事件
  let times = new Date().getTime() - (this._last_clickTime || 0)
  if (this._last_clickTime && times < 300) {
    // 屏蔽了单击时间很近的点
    return true
  }
  this._last_clickTime = new Date().getTime()

  if (
    this._last_clickPositionX &&
    Math.abs(this._last_clickPositionX - movement.x) < 10 &&
    Math.abs(this._last_clickPositionY - movement.y) < 10
  ) {
    // 屏蔽了单击像素很近的点
    return true
  }
  this._last_clickPositionX = movement.x
  this._last_clickPositionY = movement.y
  //上面代码是 避免双击带来的2个重复点

  return false
}
